package org.infodavid.common.model.impl;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.infodavid.common.model.IOrganization;
import org.infodavid.common.model.IPerson;
import org.infodavid.common.model.IUser;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

/**
 * The Class OrganizationImpl.
 */
public class OrganizationImpl extends AbstractEntity implements IOrganization {

	/** serialVersionUID. */
	private static final long serialVersionUID = -1834006673479268213L;

	/** The main site. */
	private IOrganization mainSite;

	/** The director. */
	private IPerson director;

	/** The registration date. */
	private DateTime registrationDate;

	/** The business type. */
	private String businessType;

	/** The legal form. */
	private ELegalForm legalForm;

	/** The contacts. */
	private Map<Long,IUser> contacts;

	/**
	 * The Constructor.
	 * @throws Exception the exception
	 */
	protected OrganizationImpl() throws Exception {
		super();
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganization#getMainSite()
	 */
	@Override
	public IOrganization getMainSite() {
		return mainSite;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IBasicDataObject#init()
	 */
	@Override
	public void init() throws Exception {
		super.init();

		mainSite = null;
		registrationDate = null;
		businessType = null;
		legalForm = null;
		contacts = new HashMap<Long,IUser>();
		director = null;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see
	 * org.infodavid.common.model.IOrganization#setMainSite(org.infodavid.common.model.IOrganization)
	 */
	@Override
	public void setMainSite(final IOrganization value) {
		if (!equals(mainSite, value)) {
			final Object old = mainSite;
			mainSite = value;
			markModified(MAIN_SITE, old, value);
		}
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.impl.model.DataObjectImpl#toString(java.lang.StringBuffer)
	 */
	@Override
	protected StringBuffer toString(final StringBuffer builder) {
		super.toString(builder);

		builder.append(" [registrationDate=");
		builder.append(registrationDate);
		builder.append(",businessType=");
		builder.append(businessType);
		builder.append(",legalForm=");
		builder.append(legalForm);
		builder.append(",director=");

		if (director == null) {
			builder.append("null");
		}
		else {
			builder.append(director.getKey());
		}

		builder.append(",mainSite=");

		if (mainSite == null) {
			builder.append("null");
		}
		else {
			builder.append(mainSite.getKey());
		}

		builder.append(",contacts=");

		if (contacts == null) {
			builder.append("null");
		}
		else {
			final Iterator<IUser> ite = contacts.values().iterator();

			if (ite.hasNext()) {
				builder.append(ite.next().getKey());

				while (ite.hasNext()) {
					builder.append(',');
					builder.append(ite.next().getKey());
				}
			}
		}
		builder.append("]");

		return builder;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganizationSite#getDirector()
	 */
	@Override
	public IPerson getDirector() {
		return director;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganizationSite#getRegistrationDate()
	 */
	@Override
	public DateTime getRegistrationDate() {
		return registrationDate;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganizationSite#getBusinessType()
	 */
	@Override
	public String getBusinessType() {
		return businessType;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganization#getLegalForm()
	 */
	@Override
	public ELegalForm getLegalForm() {
		return legalForm;
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see
	 * org.infodavid.common.model.IOrganizationSite#setDirector(org.infodavid.common.model.IPerson)
	 */
	@Override
	public void setDirector(final IPerson value) {
		if (!equals(director, value)) {
			final Object old = director;
			director = value;
			markModified(DIRECTOR, old, director);
		}
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganizationSite#setRegistrationDate(org.joda.time.DateTime)
	 */
	@Override
	public void setRegistrationDate(final DateTime value) {
		if (!equals(registrationDate, value)) {
			final Object old = registrationDate;
			registrationDate = value;
			markModified(REGISTRATION_DATE, old, registrationDate);
		}
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganization#setBusinessType(java.lang.String)
	 */
	@Override
	public void setBusinessType(final String value) {
		if (!equals(businessType, value)) {
			final Object old = businessType;
			businessType = value;
			markModified(TYPE, old, businessType);
		}
	}

	/*
	 * See super class or interface. (non-Javadoc)
	 * @see
	 * org.infodavid.common.model.IOrganization#setLegalForm(org.infodavid.common.model.IOrganization.
	 * ELegalForm)
	 */
	@Override
	public void setLegalForm(final ELegalForm value) {
		if (!equals(legalForm, value)) {
			final Object old = legalForm;
			legalForm = value;
			markModified(LEGAL_FORM, old, legalForm);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.impl.DataObjectImpl#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;

		result = prime * result + (getIdentity() == null ? 0 : getIdentity().hashCode());
		result = prime * result + (getName() == null ? 0 : getName().hashCode());

		if (getRegistrationDate() == null) {
			result = prime * result;
		}
		else {
			result = prime * result + getRegistrationDate().toDateTime(DateTimeZone.UTC).hashCode();
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.impl.DataObjectImpl#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}

		if (obj == null) {
			return false;
		}

		if (!(obj instanceof IOrganization)) {
			return false;
		}

		final IOrganization other = (IOrganization)obj;

		if (getIdentity() == null) {
			if (other.getIdentity() != null) {
				return false;
			}
		}
		else if (!getIdentity().equals(other.getIdentity())) {
			return false;
		}

		if (getName() == null) {
			if (other.getName() != null) {
				return false;
			}
		}
		else if (!getName().equals(other.getName())) {
			return false;
		}

		if (getRegistrationDate() == null) {
			if (other.getRegistrationDate() != null) {
				return false;
			}
		}
		else if (!getRegistrationDate().equals(other.getRegistrationDate())) {
			return false;
		}

		return true;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganization#addContact(org.infodavid.common.model.s. IUser )
	 */
	@Override
	public void addContact(final IUser value) {
		getContacts().put(value.getKey(), value);
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganization#getContacts()
	 */
	@Override
	public Map<Long,IUser> getContacts() {
		return contacts;
	}

	/*
	 * (non-Javadoc)
	 * @see org.infodavid.common.model.IOrganization#removeContact(org.infodavid.common.model.s.
	 * IUser)
	 */
	@Override
	public boolean removeContact(final IUser value) {
		return value.equals(getContacts().remove(value.getKey()));
	}

	/**
	 * Sets the contacts.
	 * @param values the values
	 */
	protected void setContacts(final Map<Long,IUser> values) {
		final Object old = contacts;
		contacts = values;
		markModified(CONTACTS, old, contacts);
	}
}
